/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modbusTCP.EntranceTCP;
import me.zhengjie.pojo.StringPPInfo;
import me.zhengjie.ppService.PPInBoundService;
import me.zhengjie.ppService.PPStationService;
import me.zhengjie.ppService.PpPalletService;
import me.zhengjie.pojo.InBoundInfo;
import me.zhengjie.pojo.PPOutBoundInvertoryUI;
import me.zhengjie.pojo.Resp;
import me.zhengjie.pojo.sqlServer.*;
import me.zhengjie.repository.*;
import me.zhengjie.service.PPInfoService;
import me.zhengjie.service.PPStorageService;
import me.zhengjie.service.dto.PPInfoDto;
import me.zhengjie.service.dto.PPInfoQueryCriteria;
import me.zhengjie.service.dto.PPInventoryDto;
import me.zhengjie.service.dto.PPOutboundOrderDetailQueryCriteria;
import me.zhengjie.service.mapper.PPInfoMapper;
import me.zhengjie.service.mapper.PPInventoryMapper;
import me.zhengjie.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author xinglin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2024-08-03
 **/
@Service
@RequiredArgsConstructor
public class PPInfoServiceImpl implements PPInfoService {

    private final PPInfoRepository ppInfoRepository;
    private final PPInfoMapper ppInfoMapper;
    private final PPInventoryRepository ppInventoryRepository;
    private final PPTimeConfigRepository ppTimeConfigRepository;
    private final PPInBoundService ppInBoundService;
    private final PPStorageService ppStorageService;
    private final PpPalletService ppPalletService;
    private final PpPalletRepository ppPalletRepository;
    private final PPOutboundOrderDetailRepository ppOutboundOrderDetailRepository;
    private final PPStationRepository ppStationRepository;
    private final EntranceTCP entranceTCP;
    private final PPStationService ppStationService;
    private final PPInventoryMapper ppInventoryMapper;


    private static final Logger ppLog = LoggerFactory.getLogger("pp");


    @Override
    public PageResult<PPOutBoundInvertoryUI> queryAll(PPInfoQueryCriteria criteria, Pageable pageable) {
//        Page<PPInfo> page = ppInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
//        return PageUtil.toPage(page.map(ppInfoMapper::toDto));
        //设置查询条件：在库状态为0-在库，锁定状态为1-启用
        criteria.setStayStatus(0);
        criteria.setLockStatus(1);
        //根据查询条件查询PPInventory实体类
        Page<PPInventory> page = ppInventoryRepository
                .findAll((root, criteriaQuery, criteriaBuilder)
                        -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);

        //将查询结果转换为PPOutBoundInvertoryUI实体类
        return PageUtil.toPage(page.map(x -> {
            PPOutBoundInvertoryUI ppOutBoundInvertoryUI = new PPOutBoundInvertoryUI();
            //根据批次号查询PPInfo实体类
            PPInfo ppInfo = ppInfoRepository.getPPInfoByPpBatch(x.getPpBatch());
            //如果查询结果不为空，则将PPInfo实体类的属性赋值给PPOutBoundInvertoryUI实体类
            if (!BeanUtil.isEmpty(ppInfo)) {
//                //截取-前的内容
//                String ppBatch = ppInfo.getPpBatch();
//                int index = ppBatch.indexOf("-");
//                if (index != -1) {
//                    ppBatch = ppBatch.substring(0, index);
//                }
                ppOutBoundInvertoryUI.setId(ppInfo.getId());
                ppOutBoundInvertoryUI.setPp(ppInfo.getPp());
                ppOutBoundInvertoryUI.setQty(ppInfo.getPpQty());
                ppOutBoundInvertoryUI.setExpTime(ppInfo.getPpExp());
                ppOutBoundInvertoryUI.setMethod(ppInfo.getMethod());
                ppOutBoundInvertoryUI.setPpBatch(ppInfo.getPpBatch());
                ppOutBoundInvertoryUI.setBatch(ppInfo.getBatch());
                ppOutBoundInvertoryUI.setPpDevice(ppInfo.getPpDevice());
                ppOutBoundInvertoryUI.setPdTime(ppInfo.getPpPd());
                ppOutBoundInvertoryUI.setDateStatus(x.getDateStatus());
            }
            return ppOutBoundInvertoryUI;
        }));
    }

    //连表查询
    @Override
    public PageResult<PPInventoryDto> queryAllbyjoin(PPInfoQueryCriteria criteria, Pageable pageable) {
        //只显示未出库的库存
        criteria.setStayStatus(0);
        Page<PPInventory> page = ppInventoryRepository.findAll(
                withCriteria(criteria),
                pageable
        );

        return PageUtil.toPage(page.map(
                x -> {
                    PPInventoryDto ppInventoryDto = new PPInventoryDto();
                    BeanUtils.copyProperties(x, ppInventoryDto);
                    ppInventoryDto.setPpinfo(x.getPpInfo());
                    return ppInventoryDto;
                }
        ));

    }


    public static Specification<PPInventory> withCriteria(PPInfoQueryCriteria criteria) {
        return (root, query, cb) -> {
            // 关联表
            Join<PPInventory, PPinfoJoin> ppInfoJoin = root.join("ppInfo", JoinType.LEFT);

            List<Predicate> predicates = new ArrayList<>();

            // ========== 主表(PPInventory)查询条件 ==========
            // ID精确查询
//            if (criteria.getId() != null) {
//                predicates.add(cb.equal(root.get("id"), criteria.getId()));
//            }

            // 批次号模糊查询
            if (StringUtils.isNotBlank(criteria.getBatch())) {
                predicates.add(cb.like(root.get("batch"), "%" + criteria.getBatch() + "%"));
            }

            // PP批次号精确查询
            if (StringUtils.isNotBlank(criteria.getPp())) {
                predicates.add(cb.like(root.get("pp"), "%" + criteria.getPp() + "%"));
            }

            // 板子批次号精确查询
            if (StringUtils.isNotBlank(criteria.getPpBatch())) {
                predicates.add(cb.like(root.get("ppBatch"), "%" + criteria.getPpBatch() + "%"));
            }

            // 载盘编码模糊查询
            if (StringUtils.isNotBlank(criteria.getPalletCode())) {
                predicates.add(cb.like(root.get("palletCode"), "%" + criteria.getPalletCode() + "%"));
            }

            // 储位号模糊查询
            if (StringUtils.isNotBlank(criteria.getStorageCode())) {
                predicates.add(cb.like(root.get("storageCode"), "%" + criteria.getStorageCode() + "%"));
            }

            // 数量范围查询
            if (criteria.getPpQty() != null) {
                predicates.add(cb.ge(root.get("qty"), criteria.getPpQty()));
            }
//            if (criteria.getMaxQty() != null) {
//                predicates.add(cb.le(root.get("qty"), criteria.getMaxQty()));
//            }

            // 入库时间范围
            if (criteria.getInBoundTime() != null) {
                LocalDateTime startOfDay = criteria.getInBoundTime().toLocalDate().atStartOfDay(); // 当天的开始时间
//                LocalDateTime endOfDay = criteria.getInBoundTime().toLocalDate().atTime(LocalTime.MAX); // 当天的结束时间 (23:59:59.999999999)
                LocalDateTime endOfDay = LocalDateTime.of(criteria.getInBoundTime().toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                predicates.add(cb.greaterThanOrEqualTo(root.get("inBoundTime"), startOfDay));
                predicates.add(cb.lessThanOrEqualTo(root.get("inBoundTime"), endOfDay));
            }

            // 出库时间范围
            if (criteria.getOutBoundTime() != null) {
                LocalDateTime startOfDay = criteria.getOutBoundTime().toLocalDate().atStartOfDay(); // 当天的开始时间
//                LocalDateTime endOfDay =  LocalDateTime.of(criteria.getOutBoundTime().toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                LocalDateTime endOfDay = LocalDateTime.of(criteria.getOutBoundTime().toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                predicates.add(cb.greaterThanOrEqualTo(root.get("outBoundTime"), startOfDay));
                predicates.add(cb.lessThanOrEqualTo(root.get("outBoundTime"), endOfDay));
            }

            // 是否打包
            if (criteria.getIsPakage() != null) {
                predicates.add(cb.equal(root.get("isPakage"), criteria.getIsPakage()));
            }

            // 日期状态
            if (StringUtils.isNotBlank(criteria.getDateStatus())) {
                predicates.add(cb.equal(root.get("dateStatus"), criteria.getDateStatus()));
            }

            // 在库状态
            if (criteria.getStayStatus() != null) {
                predicates.add(cb.equal(root.get("stayStatus"), criteria.getStayStatus()));
            }

            // 锁定状态
            if (criteria.getLockStatus() != null) {
                predicates.add(cb.equal(root.get("lockStatus"), criteria.getLockStatus()));
            }


            // ========== 关联表(PPInfo)查询条件 ==========
            // 材质查询
            if (StringUtils.isNotBlank(criteria.getPpMaterial())) {
                predicates.add(cb.like(ppInfoJoin.get("ppMaterial"), "%" + criteria.getPpMaterial() + "%"));
            }

            // 型号查询
            if (StringUtils.isNotBlank(criteria.getPpModel())) {
                predicates.add(cb.like(ppInfoJoin.get("ppModel"), "%" + criteria.getPpModel() + "%"));
            }

            // 厂商查询
            if (StringUtils.isNotBlank(criteria.getPpMfrs())) {
                predicates.add(cb.like(ppInfoJoin.get("ppMfrs"), "%" + criteria.getPpMfrs() + "%"));
            }

            // 尺寸查询
            if (StringUtils.isNotBlank(criteria.getPpSize())) {
                predicates.add(cb.like(ppInfoJoin.get("ppSize"), "%" + criteria.getPpSize() + "%"));
            }

            // rc
            if (StringUtils.isNotBlank(criteria.getRc())) {
                predicates.add(cb.like(ppInfoJoin.get("rc"), "%" + criteria.getRc() + "%"));
            }

            // 孔类型
            if (StringUtils.isNotBlank(criteria.getPpHole())) {
                predicates.add(cb.like(ppInfoJoin.get("ppHole"), "%" + criteria.getPpHole() + "%"));
            }


            // 生产日期范围
            if (criteria.getPpPd() != null) {
                String Time = criteria.getPpPd();
                //前后时间用T分割
                String[] split = Time.split(",");
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime start = LocalDateTime.parse(split[0] + " 00:00:00", formatter);
                LocalDateTime end = LocalDateTime.parse(split[1] + " 00:00:00", formatter);
                LocalDateTime startOfDay = start.toLocalDate().atStartOfDay(); // 当天的开始时间

//                LocalDateTime endOfDay = criteria.getPpPd().toLocalDate().atTime(LocalTime.MAX); // 当天的结束时间 (23:59:59.999999999)
                LocalDateTime endOfDay = LocalDateTime.of(end.toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                predicates.add(cb.greaterThanOrEqualTo(ppInfoJoin.get("ppPd"), startOfDay));
                predicates.add(cb.lessThanOrEqualTo(ppInfoJoin.get("ppPd"), endOfDay));
            }

            // 过期日期范围
            if (criteria.getPpExp() != null) {
                String Time = criteria.getPpExp();
                String[] split = Time.split(",");
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime start = LocalDateTime.parse(split[0] + " 00:00:00", formatter);
                LocalDateTime end = LocalDateTime.parse(split[1] + " 00:00:00", formatter);

                LocalDateTime startOfDay = start.toLocalDate().atStartOfDay(); // 当天的开始时间
//                LocalDateTime endOfDay = criteria.getPpExp().toLocalDate().atTime(LocalTime.MAX); // 当天的结束时间 (23:59:59.999999999)
                LocalDateTime endOfDay = LocalDateTime.of(end.toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                predicates.add(cb.greaterThanOrEqualTo(ppInfoJoin.get("ppExp"), startOfDay));
                predicates.add(cb.lessThanOrEqualTo(ppInfoJoin.get("ppExp"), endOfDay));
            }

            if (criteria.getPpPack() != null) {
                String Time = criteria.getPpPack();
                String[] split = Time.split(",");
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime start = LocalDateTime.parse(split[0] + " 00:00:00", formatter);
                LocalDateTime end = LocalDateTime.parse(split[1] + " 00:00:00", formatter);

                LocalDateTime startOfDay = start.toLocalDate().atStartOfDay(); // 当天的开始时间
//                LocalDateTime endOfDay = criteria.getPpExp().toLocalDate().atTime(LocalTime.MAX); // 当天的结束时间 (23:59:59.999999999)
                LocalDateTime endOfDay = LocalDateTime.of(end.toLocalDate(), LocalTime.of(23, 59, 59)); // 当天的结束时间 (23:59:59.999999999)
                predicates.add(cb.greaterThanOrEqualTo(ppInfoJoin.get("ppPack"), startOfDay));
                predicates.add(cb.lessThanOrEqualTo(ppInfoJoin.get("ppPack"), endOfDay));
            }

            // 作业人员查询
            if (StringUtils.isNotBlank(criteria.getPpWorker())) {
                predicates.add(cb.like(ppInfoJoin.get("ppWorker"), "%" + criteria.getPpWorker() + "%"));
            }

            // 是否打包查询
            if (criteria.getIsPakage() != null) {
                predicates.add(cb.equal(ppInfoJoin.get("isPakage"), criteria.getIsPakage()));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }


    @Override
    // 根据订单详情查询所有PP出库订单
    public PageResult<PPOutBoundInvertoryUI> queryAllByOrderDetails(PPOutboundOrderDetailQueryCriteria criteria, Pageable pageable, Integer orderId) {

        // 设置出库订单ID
        criteria.setOutBoundOrderId(orderId);
        // 查询出库订单详情
        Page<PPOutboundOrderDetail> page = ppOutboundOrderDetailRepository
                .findAll((root, criteriaQuery, criteriaBuilder)
                        -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);

        // 返回分页结果
        return PageUtil.toPage(page.map(x -> {

            // 创建PP出库库存UI对象
            PPOutBoundInvertoryUI ppOutBoundInvertoryUI = new PPOutBoundInvertoryUI();
            // 根据栈板码查询库存
            String ppBatch = ppInventoryRepository.findPPInventoryByPalletCode(x.getPalletCode()).getPpBatch();
            // 根据批次查询PP信息
            PPInfo ppInfo = ppInfoRepository.getPPInfoByPpBatch(ppBatch);
            if (!BeanUtil.isEmpty(ppInfo)) {
                // 设置ID
                ppOutBoundInvertoryUI.setId(ppInfo.getId());
                // 设置数量
                ppOutBoundInvertoryUI.setQty(ppInfo.getPpQty());
                // 设置过期时间
                ppOutBoundInvertoryUI.setExpTime(ppInfo.getPpExp());
                // 设置方法
                ppOutBoundInvertoryUI.setMethod(ppInfo.getMethod());
                // 设置批次
                ppOutBoundInvertoryUI.setPpBatch(ppInfo.getPpBatch());
                //设置产品批次号
                ppOutBoundInvertoryUI.setBatch(ppInfo.getBatch());
                // 设置设备
                ppOutBoundInvertoryUI.setPpDevice(ppInfo.getPpDevice());
                // 设置生产日期
                ppOutBoundInvertoryUI.setPdTime(ppInfo.getPpPd());
            }
            // 返回PP出库库存UI对象
            return ppOutBoundInvertoryUI;

        }));
    }

    @Override
    public List<PPInfoDto> queryAll(PPInfoQueryCriteria criteria) {
        return ppInfoMapper.toDto(ppInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public PPInfoDto findById(Integer id) {
        PPInfo ppInfo = ppInfoRepository.findById(id).orElseGet(PPInfo::new);
        ValidationUtil.isNull(ppInfo.getId(), "PpInfo", "id", id);
        return ppInfoMapper.toDto(ppInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(PPInfo resources) {
        ppInfoRepository.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(PPInfo resources) {
        PPInfo ppInfo = ppInfoRepository.findById(resources.getId()).orElseGet(PPInfo::new);
        ValidationUtil.isNull(ppInfo.getId(), "PpInfo", "id", resources.getId());
        ppInfo.copy(resources);
        ppInfoRepository.save(ppInfo);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            ppInfoRepository.deleteById(id);
            PPInfo ppInfo = ppInfoRepository.getById(id);
            //把ppTimeConfig表中的数据删除
            ppTimeConfigRepository.deleteByPPBatch(ppInfo.getPpBatch());

        }
    }

    @Override
    public void download(List<PPInfoDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (PPInfoDto ppInfo : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("产品批次号", ppInfo.getBatch());
            map.put("pp批次号", ppInfo.getPpBatch());
            map.put("材质", ppInfo.getPpMaterial());
            map.put("型号", ppInfo.getPpModel());
            map.put("厂商", ppInfo.getPpMfrs());
            map.put("尺寸", ppInfo.getPpSize());
            map.put("数量", ppInfo.getPpQty());
            map.put("生产时间", ppInfo.getPpPd());
            map.put("过期时间", ppInfo.getPpExp());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Transactional
    public void saveOrUpdatePPInfo(PPInfo ppInfo) {
        PPInfo ppInfoExist = ppInfoRepository.getPPInfoByPpBatch(ppInfo.getPpBatch());

        //如果不存在，则保存新的ppInfo
        if (BeanUtil.isEmpty(ppInfoExist)) {
            //使用ppBacth+时间搓的方式生成唯一字段
            String ppBatch = ppInfo.getPpBatch() + "-" + System.currentTimeMillis();

            ppInfo.setPpBatch(ppBatch);
            ppInfoRepository.save(ppInfo);
            //默认设置pp预警和超期的时间为72和96小时
            PPTimeConfig ppTimeConfig = new PPTimeConfig();
            ppTimeConfig.setPpBatch(ppInfo.getPpBatch());
            ppTimeConfig.setWarningTime(72);
            ppTimeConfig.setAlarmTime(96);
            ppTimeConfigRepository.save(ppTimeConfig);

        } else {
            //如果存在，则更新ppInfo
            int id = ppInfoExist.getId();
            BeanUtils.copyProperties(ppInfo, ppInfoExist);
            ppInfoExist.setId(id);
            ppInfoRepository.save(ppInfoExist);

        }


    }

    @Override
    public PPInfo queryById(Integer id) {

        return ppInfoRepository.findById(id).orElseGet(PPInfo::new);

    }

    @Override
    public PPInfo queryByPalletCode(String palletCode) {

        PpPallet ppPallet = ppPalletRepository.findByPalletCode(palletCode);
        PPInfo info = ppInfoRepository.getPPInfoByPpBatch(ppPallet.getPpBatch());
        return info;
    }

//    @Override
//    public List<PPInfo> findByPpBatch(List<String> ppBatchs) {
//        List<PPInfo> ppInfos = new ArrayList<>();
//        for (String ppBatch : ppBatchs) {
//             PPInfo ppInfo = ppInfoRepository.findByPpBatch(ppBatch);
//             if (ppInfo != null){
//                ppInfos.add(ppInfo);
//             }
//        }
//
//        if (ppInfos.size() == 0) {
//            throw new BadRequestException("未找到对应的pp信息");
//        }
//
//        return  ppInfos;
//    }


    @Override
    @Transactional
    public Resp saveOrUpdate(InBoundInfo inBoundInfo) {
        try {

            //查看对应的库存是否过期
            PPInventory ppInventory = ppInventoryRepository.findByPpBatch(inBoundInfo.getPpInfo().getPpBatch());

            //先看有没有对应的库存
            if (ObjectUtil.isNotEmpty(ppInventory)) {
                if (ppInventory.getExpTime().isBefore(LocalDateTime.now())) {
                    //抛错
                    throw new RuntimeException(inBoundInfo.getPpInfo().getPpBatch() + "物料已过期，请联系管理人员处理");
                }
            }

            if (inBoundInfo.getIsPackage() == 0) {
                if (ObjectUtil.isNotEmpty(ppInventory)) {
                    if (ppInventory.getOutTime().isBefore(LocalDateTime.now())) {
                        //抛错
                        throw new RuntimeException(inBoundInfo.getPpInfo().getPpBatch() + "物料已超期，请先打包再入库");
                    }
                }
            }

            //先查看对应的工作是否被锁定而且是右侧工作站
            PPStation ppStation = ppStationRepository.findPPStationsByStationCode(inBoundInfo.getStationCode());
            if (ppStation.getTakeStatus() == 1 && ppStation.getStationType() == 1) {
                return Resp.builder().status(500).msg("该工作站有正在执行的出库任务，请稍后再入库").build();
            }

            Resp validateResp = validateInBoundInfo(inBoundInfo);
            if (validateResp != null) {
                return validateResp;
            }

            // 转换PPInfo
            PPInfo ppInfo = transformInfo(inBoundInfo.getPpInfo());

            ppInfo.setIsPakage(inBoundInfo.getIsPackage());

            // 保存ppinfo信息
            this.saveOrUpdatePPInfo(ppInfo);

            // 检查载盘信息是否存在
            if (ObjectUtils.isEmpty(ppPalletService.findByPalletCode(inBoundInfo.getPalletCode()))) {
                //如果信息不存在就新增载具
                PpPallet ppPallet = new PpPallet();
                ppPallet.setPalletCode(inBoundInfo.getPalletCode());
                ppPallet.setCreateTime(LocalDateTime.now());
                ppPallet.setPpBatch(ppInfo.getPpBatch());
                ppPalletRepository.save(ppPallet);
            } else {
                // 保存信息
                PpPallet ppPallet = ppPalletService.findByPalletCode(inBoundInfo.getPalletCode());
                ppPallet.setPpBatch(ppInfo.getPpBatch());
                ppPallet.setCreateTime(LocalDateTime.now());
                ppPalletRepository.save(ppPallet);
            }

            // 生成入库任务
            ppInBoundService.createInboundMission(inBoundInfo.getPalletCode(), inBoundInfo.getStationCode());


            return Resp.builder().status(200).msg("生成入库任务成功").build();


        } catch (Exception e) {
            ppLog.error("生成入库任务失败", e);
            return Resp.builder().status(500).msg(e.getMessage()).build();
        }
    }

    /**
     * 对校验入库信息进行校验，如果校验不通过，则返回错误信息
     *
     * @param inBoundInfo
     * @return
     */
    public Resp validateInBoundInfo(InBoundInfo inBoundInfo) {
        if (StringUtils.isBlank(inBoundInfo.getPalletCode())) {
            return Resp.builder().status(501).msg("载盘编码不能为空").build();
        }
        if (StringUtils.isBlank(inBoundInfo.getStationCode())) {
            return Resp.builder().status(502).msg("工作站编码不能为空").build();
        }
        if (ObjectUtils.isEmpty(inBoundInfo.getPpInfo())) {
            return Resp.builder().status(503).msg("pp信息不能为空").build();
        }
        // 检查是否有可用储位
        if (ppStorageService.findSuitableStorage().size() == 0) {
            return Resp.builder().status(504).msg("没有可用储位，生成入库任务失败").build();
        }

//        // 检查载盘信息是否存在
//        if (ObjectUtils.isEmpty(ppPalletService.findByPalletCode(inBoundInfo.getPalletCode()))) {
//            return Resp.builder().status(505).msg("该载盘信息不存在，生成入库任务失败,请核实载盘码是否正确").build();
//        }

        // 检查载盘是否在储位中
        if (!ObjectUtils.isEmpty(ppStorageService.findPPStorageByPalletCode(inBoundInfo.getPalletCode()))) {
            return Resp.builder().status(506).msg("该载盘记录在储位中，生成入库任务失败，请核实载盘的实际位置").build();
        }

        return null;
    }

    /**
     * 校验 inBoundInfo 对象中的字段是否为 null 或空（针对字符串）
     *
     * @param inBoundInfo 需要校验的对象
     * @return 如果校验通过，返回 null；如果校验失败，返回错误信息
     */
    public String validatePPInfo(InBoundInfo inBoundInfo) {


        PPInfo ppInfo = transformInfo(inBoundInfo.getPpInfo());
        if (ppInfo == null) {
            return "PPInfo 对象不能为 null";
        }

        StringBuilder errorMsg = new StringBuilder();

        if (inBoundInfo.getPalletCode()
                == null || inBoundInfo.getPalletCode().trim().isEmpty()) {
            errorMsg.append("载盘码不能为空; ");
        }

        if (inBoundInfo.getStationCode() == null || inBoundInfo.getStationCode().trim().isEmpty()) {
            errorMsg.append("工作站编码不能为空; ");
        }

        // 校验 pp 字段
        if (ppInfo.getPp() == null || ppInfo.getPp().trim().isEmpty()) {
            errorMsg.append("pp批次号不能为空; ");
        }

        // 校验 batch 字段
        if (ppInfo.getBatch() == null || ppInfo.getBatch().trim().isEmpty()) {
            errorMsg.append("工程号不能为空; ");
        }

        // 校验 ppBatch 字段
        if (ppInfo.getPpBatch() == null || ppInfo.getPpBatch().trim().isEmpty()) {
            errorMsg.append("板子批号不能为空; ");
        }

        // 校验 ppQty 字段
        if (ppInfo.getPpQty() == null) {
            errorMsg.append("数量不能为空; ");
        }

        // 校验 ppPd 字段
        if (ppInfo.getPpPd() == null) {
            errorMsg.append("生产时间不能为空; ");
        }

        // 校验 ppExp 字段
        if (ppInfo.getPpExp() == null) {
            errorMsg.append("过期时间不能为空; ");
        }

        // 以下字段暂时不用校验
/*
        // 校验 ppMaterial 字段
        if (ppInfo.getPpMaterial() == null || ppInfo.getPpMaterial().trim().isEmpty()) {
            errorMsg.append("材质不能为空; ");
        }

        // 校验 ppModel 字段
        if (ppInfo.getPpModel() == null || ppInfo.getPpModel().trim().isEmpty()) {
            errorMsg.append("型号不能为空; ");
        }

        // 校验 ppMfrs 字段
        if (ppInfo.getPpMfrs() == null || ppInfo.getPpMfrs().trim().isEmpty()) {
            errorMsg.append("厂商不能为空; ");
        }

        // 校验 ppSize 字段
        if (ppInfo.getPpSize() == null) {
            errorMsg.append("尺寸不能为空; ");
        }

        // 校验 ppWorker 字段
        if (ppInfo.getPpWorker() == null || ppInfo.getPpWorker().trim().isEmpty()) {
            errorMsg.append("作业人员不能为空; ");
        }

        // 校验 ppDevice 字段
        if (ppInfo.getPpDevice() == null || ppInfo.getPpDevice().trim().isEmpty()) {
            errorMsg.append("作业设备不能为空; ");
        }

        // 校验 method 字段
        if (ppInfo.getMethod() == null || ppInfo.getMethod().trim().isEmpty()) {
            errorMsg.append("定位方式不能为空; ");
        }*/

        // 如果 errorMsg 不为空，说明有错误
        if (errorMsg.length() > 0) {
            return errorMsg.toString();
        }

        // 校验通过
        return null;
    }

    @Override
    public PPInfo transformInfo(StringPPInfo source) {
        if (source == null) {
            return null;
        }

        PPInfo target = new PPInfo();

        // 直接映射的属性
        target.setPp(source.getPp());
        target.setBatch(source.getBatch());
        target.setPpBatch(source.getPpBatch());
        target.setPpMaterial(source.getPpMaterial());
        target.setPpModel(source.getPpModel());
        target.setPpMfrs(source.getPpMfrs());
        target.setPpSize(source.getPpSize()); // 不转换 ppSize
        target.setPpWorker(source.getPpWorker());
        target.setPpDevice(source.getPpDevice());
        target.setMethod(source.getMethod());
        target.setRc(source.getRc());
        target.setPpHole(source.getPpHole());

        // 转换 ppQty
        target.setPpQty(parseInteger(source.getPpQty()));

        // 转换 ppPd 和 ppExp
        target.setPpPd(parseDate(source.getPpPd()));
        target.setPpExp(parseDate(source.getPpExp()));

        //转换 ppPack时间
//        target.setPpExp(parsePackDate(source.getPpPack()));
        target.setPpExp(parseDate(source.getPpPack()));

        return target;
    }

    // 定义日期格式
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 将字符串转换为 Integer
     */
    private static Integer parseInteger(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid integer value: " + value);
        }
    }

    /**
     * 将字符串转换为 LocalDateTime
     * 输入格式为 "yyyy-MM-dd"，输出格式为 "yyyy-MM-dd 00:00:00"
     */
    private static LocalDateTime parseDate(String value) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        try {
            // 尝试解析字符串

            return LocalDateTime.parse(value, formatter); // 如果解析成功，返回 LocalDateTime
        } catch (Exception e1) {
            if (value == null || value.trim().isEmpty()) {
                return null;
            }
            try {
                // 将 "yyyy-MM-dd" 转换为 "yyyy-MM-dd 00:00:00"
                String dateTimeString = value + " 00:00:00";
                return LocalDateTime.parse(dateTimeString, DATE_FORMATTER);
            } catch (Exception e2) {
                throw new IllegalArgumentException("Invalid date format. Expected 'yyyy-MM-dd'");
            } // 如果解析失败，返回补全LocalDateTime
        }

    }


    /**
     * 将字符串转换为 LocalDateTime
     * 输入格式为 "yyyyMMdd 00:00:00"，输出格式为 "yyyy-MM-dd 00:00:00"
     */
    private static LocalDateTime parsePackDate(String value) {
        String datePart = value.substring(0, 17);
        value = datePart.substring(0, 4) + "-" + datePart.substring(4, 6) + "-" + datePart.substring(6, 17);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        try {
            // 尝试解析字符串
            return LocalDateTime.parse(value, formatter); // 如果解析成功，返回 LocalDateTime
        } catch (Exception e1) {
            if (value == null || value.trim().isEmpty()) {
                return null;
            }
            try {
                // 将 "yyyyMMdd" 转换为 "yyyy-MM-dd 00:00:00"
                String dateTimeString = value + " 00:00:00";
                return LocalDateTime.parse(dateTimeString, DATE_FORMATTER);
            } catch (Exception e2) {
                throw new IllegalArgumentException("Invalid date format. Expected 'yyyy-MM-dd'");
            } // 如果解析失败，返回补全LocalDateTime
        }

    }

}